﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_GL_TEXTURE_H
#define _UXS_GL_TEXTURE_H

#pragma once

#include "GLSampler.h"
#include "GLRenderBuffer.h"
#include "GLMesh.h"

namespace UX_STL
{
namespace GLShell
{

	//
	// Texture Swizzle Flags
	//

	struct GLTexSwizzle
	{
		// input channels
		enum EChannel : uint8
		{
			ZERO	= 0,
			ONE		= 1,
			R,
			G,
			B,
			A
		};

		struct def
		{
			enum type : uint16
			{
				// default swizzle
				AUTO		= 0,
				c000R		= 0x0002,
				c111R		= 0x1112,
				cR000		= 0x2000,
				cRRRR		= 0x2222,
				cRRRG		= 0x2223,
				cGGGR		= 0x3332,
				cRG00		= 0x2300,
				cRG11		= 0x2311,
				cRGB0		= 0x2340,
				cRGB1		= 0x2341,
				cBGR0		= 0x4320,
				cBGR1		= 0x4321,
				cRGBA		= 0x2345,
				cBGRA		= 0x4325,
				cARGB		= 0x5234,
				cABGR		= 0x5432,
			};
		};

		// output channels
		uint16		chR	: 4,
					chG	: 4,
					chB	: 4,
					chA	: 4;
		///
		GLTexSwizzle():  chR(R), chG(G), chB(B), chA(A) {}
		GLTexSwizzle(const def::type s):  chR(s>>12), chG(s>>8), chB(s>>4), chA(s) {}
		GLTexSwizzle(const GLint aSwizzle[4]) { FromArray( aSwizzle ); }

		bool operator == (const GLTexSwizzle &right) const;
		bool operator != (const GLTexSwizzle &right) const;
		void ToArray(GLint aSwizzle[4]) const;
		void FromArray(const GLint aSwizzle[4]);
	};



	//
	// Texture Format Info
	//

	struct GLTexFormatInfo
	{
		struct GLTextureBufferFormat;

		struct GLInternalFormatInfo
		{
			enum EType
			{
				R	= 0,
				G,
				B,
				A,
				DEPTH,
				STENCIL,
				SHARED,
				_SIZE,
			};

			struct TComponentInfo
			{
				bool	bAvailable	: 1;		// internal format has this component
				bool	bRenderable	: 1;
				///
				TComponentInfo(): bAvailable(false), bRenderable(false) {}
			};

			typedef static_array< uint, _SIZE >						comsize_array_t;
			typedef static_array< gl_tex_component::type, _SIZE >	comptype_array_t;


			// GL_ARB_internalformat_query (GL 4.2)
			uint					uMaxSamples;

			// GL_ARB_internalformat_query2 (GL 4.3)
			comsize_array_t			aCompSize;				// size in bits of RGBA color, depth, stencil and shared components (level)
			comptype_array_t		aCompType;				// type of RGBA color, depth, stencil and shared components (level)
			uvec4					vDimensions;			// width, height, depth, layers
			uvec2					vCompressedBlockDim;	// width & height of the compressed block
			uint					uCompressedBlockSize;	// bytes per block
			uint					uTexelSize;				// bit_per_pixel
			gl_tex_iformat::type	eInternalFormat,
									ePreferredIFormat;
			gl_image_class::type	eImageClass;
			gl_pixel_format::type	ePixelFormat;
			gl_pixel::type			ePixelType;
			gl_img_fmt_compatibility::type
									eImageFormatCompatibility;
			gl_tex_view_class::type	eTexViewClass;
			gl_support::type		eFramebufferRenderable,
									eFramebufferRenderableLayered,
									eFramebufferBlend,
									eManualGenerateMipmaps,
									eAutoGenerateMipmaps,
									eSRGBRead,
									eSRGBWrite,
									eFilter,
									eTextureShadow,
									eTextureGather,
									eTextureGatherShadow,
									eShaderImageLoad,
									eShaderImageStore,
									eShaderImageAtomic,
									eSimultaneousTextureAndDepthTest,	// read from depth texture in shader and do HW depth test withoud depth write
									eSimultaneousTextureAndStencilTest,	// --//--
									eSimultaneousTextureAndDepthWrite,	// depth stencil texture: depth write enabled, stencil read in shader
									eSimultaneousTextureAndStencilWrite,// --//--
									eClearBuffer,				// for commands glClearBuffer*Data
									eTextureView;				// using with texture view
			gl_color_encoding::type	eColorEncoding;
			TComponentInfo			sColor,
									sDepth,
									sStencil;
			bool					bSupported	: 1;	// internal format supported by the GL
			bool					bReadPixels	: 1;
			bool					bMipmaps	: 1;
			bool					bCompressed	: 1;
			///
			GLInternalFormatInfo() { ZeroMem( *this ); }
		};

		static bool GetIntegnalFormatInfo(gl_texture::type eTarget, gl_tex_iformat::type eIFormat, GLInternalFormatInfo &sInfo);


		static bool IsCompressed(gl_tex_iformat::type eIFormat);
		static bool IsImageSupported(gl_tex_iformat::type eIFormat);
		static bool IsRenderableFormat(gl_tex_iformat::type eIFormat);
		static bool GetTexDataFormat(gl_tex_iformat::type eIFormat, gl_pixel_format::type &eFormat, gl_pixel::type &eType);
		static bool GetSupportedFlags(gl_tex_iformat::type eIFormat, bool &bCompressed, bool &bImageSupported, bool &bIsRanderable);
		static bool GetParams(gl_tex_iformat::type eIFormat, uint *pChannels, gl_tex_component::type *pType, uint *pBitPP, bool *pCompressed, bool *pImageSupported, bool *pRanderable);
		
		static bool GetChannels(gl_tex_iformat::type eIFormat, uint &uChannels);
		static bool GetComponentType(gl_tex_iformat::type eIFormat, gl_tex_component::type &eType);
		static bool GetBitPerPixel(gl_tex_iformat::type eIFormat, uint &uBPP);

		static bool GetBitPerPixel(gl_pixel_format::type eFormat, gl_pixel::type eType, uint &uBPP);
	};



	//
	// Base Texture
	//

	class UX_EXPORT GLTexture : public GLRenderTarget
	{
	public:
		struct GLTextureInfo
		{
			typedef GLTexFormatInfo::GLInternalFormatInfo					EType;
			typedef GLTexFormatInfo::GLInternalFormatInfo::comsize_array_t	comsize_array_t;
			typedef GLTexFormatInfo::GLInternalFormatInfo::comptype_array_t	comptype_array_t;

			uvec3					vDimension;			// dimension (level)
			ivec2					vLOD;				// min max lod (global)
			int						iBaseLevel;			// base level (global)
			uint					uSamples;			// (level)
			gl_tex_iformat::type	eIFormat;
			comsize_array_t			aCompSize;			// size in bits of RGBA color, depth, stencil and shared components (level)
			comptype_array_t		aCompType;			// type of RGBA color, depth, stencil and shared components (level)
			gl_compare::type		eCompareRTT;		// (global)
			bool					bImmutable;			// true if use glTexStorage{1,2,3}D (global)
			bool					bCompressed;		// (level)
			bool					bFixedSampleLocation;	// (level)
			///
			GLTextureInfo():
				iBaseLevel(0), eCompareRTT(gl_compare::_UNKNOWN), eIFormat(gl_tex_iformat::_UNKNOWN),
				uSamples(0), bImmutable(false), bCompressed(false), bFixedSampleLocation(false) {}
		};

	protected:
		GLuint						_uID;
		GLSamplerSW					_cSampler;
		GLTexSwizzle				_sSwizzle;
		gl_texture::type			_eTarget;			// don't change !!! (except TextureView class)
		uint16						_uMaxLevel;
		bool						_bImageSupported,	// true if texture has supported image format
									_bCompressed,
									_bRenderable;		// true if supported render to texture (with this internal format) (TODO)

	public:
		GLTexture (gl_texture::type eTarget = gl_texture::TEXTURE_2D);
		~GLTexture ();
		
		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel = 0, uint uLayer = 0);
		
		virtual bool Storage (gl_rt_format::type eFormat, const uvec3 &vDim, uint uLevels = 0, uint8 uSamples = 0);
		virtual bool CreateLevel (uint uLevel, gl_tex_iformat::type eIFormat = gl_tex_iformat::_UNKNOWN);
		virtual bool SetImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SubImage (const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SetCompressedImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
		virtual bool CompressedSubImage (gl_tex_iformat::type eFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
		virtual bool GetImageSize (usize &uSize, gl_pixel_format::type eFormat, gl_pixel::type eType, uint uLevel = 0);
		virtual bool GetImage (void *pData, gl_pixel_format::type eFormat, gl_pixel::type eType, uint uLevel = 0, gl_cube_face::type eFace = gl_cube_face::_UNKNOWN);
		virtual bool GetCompressedImageSize (usize &uSize, uint uLevel = 0);
		virtual bool GetCompressedImage (void *pData, uint uLevel = 0, gl_cube_face::type eFace = gl_cube_face::_UNKNOWN);
		//virtual bool Compress();
		//virtual bool Resize(gl_tex_iformat::type eFormat, const uvec3 &vDim);
		virtual bool CopyImage (const GLTexture *pFromTex, uint uReadLevel, const uvec3 &vReadOffset, uint uWriteLevel, const uvec3 &vWriteOffset, const uvec3 &vSize);
		virtual bool CopyScreen (const urect &sScreenSize, const uvec3 &vOffset, uint uLevel = 0);
		virtual void Destroy ();
		
		void Bind () const;
		void Bind (uint8 uStage) const;
		void Unbind (uint8 uStage) const;
		void Unbind () const;
		
		void BindImage (uint8 uStage, gl_access::type eAccess, uint uLevel = 0) const;
		void BindImage (uint8 uStage, uint uLayer, gl_access::type eAccess, uint uLevel = 0) const;
		void UnbindImage (uint8 uStage) const;

		bool GenerateMipmaps () const;
		void SetBaseLevel (int iLevel) const;
		bool SetSwizzle (GLTexSwizzle sSwizzle);
		bool SetSampler (const GLSamplerSrc &sSrc);
		bool ApplySampler (const GLSamplerSrc &sSrc) const;
		bool GetTextureInfo (GLTextureInfo &sInfo, uint uLevel = 0, gl_cube_face::type eFace = gl_cube_face::_FIRST) const;
		
		GLuint				Id ()					const	{ return _uID; }
		gl_texture::type	Target ()				const	{ return _eTarget; }
		GLTexSwizzle const&	Swizzle ()				const	{ return _sSwizzle; }
		GLSamplerSW const &	Sampler ()				const	{ return _cSampler; }
		bool				IsCompressed ()			const	{ return _bCompressed; }
		bool				IsImageSupported ()		const	{ return _bImageSupported; }
		bool				IsRenderable ()			const	{ return _bRenderable; }
		uvec3 const			LevelDimension (uint i)	const;
	};



	//
	// Texture 2D
	//

	class UX_EXPORT GLTexture2D : public GLTexture
	{
	public:
		GLTexture2D ();

		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel = 0, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples = 0);
		
		// GLTexture //
		virtual bool Storage (gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels = 0, uint8 uSamples = 0);
		virtual bool CreateLevel (uint uLevel, gl_tex_iformat::type eIFormat);
		virtual bool SetImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SubImage (const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SetCompressedImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
		virtual bool CompressedSubImage (gl_tex_iformat::type eFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
	};



	//
	// Texture Cube Map
	//

	class UX_EXPORT GLTextureCube : public GLTexture
	{
	public:
		GLTextureCube ();

		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel = 0, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples = 0);
		
		// GLTexture //
		virtual bool Storage (gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels = 0, uint8 uSamples = 0);
		virtual bool CreateLevel (uint uLevel, gl_tex_iformat::type eIFormat);
		virtual bool SetImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SubImage (const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SetCompressedImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
		virtual bool CompressedSubImage (gl_tex_iformat::type eFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
	};



	//
	// Texture 2D Array
	//

	class UX_EXPORT GLTexture2DArray : public GLTexture
	{
	public:
		GLTexture2DArray ();

		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples = 0);
		
		// GLTexture //
		virtual bool Storage (gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels = 0, uint8 uSamples = 0);
		virtual bool CreateLevel (uint uLevel, gl_tex_iformat::type eIFormat);
		virtual bool SetImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SubImage (const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SetCompressedImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
		virtual bool CompressedSubImage (gl_tex_iformat::type eFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
	};



	//
	// Texture 3D
	//

	class UX_EXPORT GLTexture3D : public GLTexture
	{
	public:
		GLTexture3D ();

		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples = 0);
		
		// GLTexture //
		virtual bool Storage (gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels = 0, uint8 uSamples = 0);
		virtual bool CreateLevel (uint uLevel, gl_tex_iformat::type eIFormat);
		virtual bool SetImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SubImage (const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SetCompressedImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
		virtual bool CompressedSubImage (gl_tex_iformat::type eFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
	};



	//
	// Texture Cube Map Array
	//

	class UX_EXPORT GLTextureCubeArray : public GLTexture
	{
	public:
		GLTextureCubeArray ();

		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples = 0);
		
		// GLTexture //
		virtual bool Storage (gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels = 0, uint8 uSamples = 0);
		virtual bool CreateLevel (uint uLevel, gl_tex_iformat::type eIFormat);
		virtual bool SetImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SubImage (const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel = 0);
		virtual bool SetCompressedImage (gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
		virtual bool CompressedSubImage (gl_tex_iformat::type eFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel = 0);
	};



	//
	// Texture 2D Multisample
	//

	class UX_EXPORT GLTexture2DMS : public GLTexture
	{
	public:
		GLTexture2DMS ();

		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel = 0, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples = 0);
		
		// GLTexture //
		virtual bool Storage (gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels = 0, uint8 uSamples = 0);
		
		bool Create (gl_rt_format::type eIFormat, const uvec2 &vDim, uint8 uCoverageSamples, uint8 uColorSamples);
	};



	//
	// Texture 2D Multisample Array
	//

	class UX_EXPORT GLTexture2DMSArray : public GLTexture
	{
	public:
		GLTexture2DMSArray ();

		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel = 0, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples = 0);

		// GLTexture //
		virtual bool Storage (gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels = 0, uint8 uSamples = 0);
		
		bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uCoverageSamples, uint8 uColorSamples);
	};



	//
	// Texture View
	//

	class UX_EXPORT GLTextureView : public GLTexture
	{
	public:
		GLTextureView ();

		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel = 0, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples = 0);

		bool Create (gl_texture::type eTarget, const GLTexture *pTexture, gl_tex_iformat::type eIFormat,
					 uint uMinLevel, uint uNumLevels, uint uMinLayer = 0, uint uNumLayers = 0);

		static bool s_CheckTargetSupport (gl_texture::type eSrcTarget, gl_texture::type eViewTarget);

		template <typename T>
		const T *	To () const	{ ASSERT( s_CheckTargetSupport( T().Target(), _eTarget ) );  return (const T *)this; }
	};



	//
	// Texture Buffer
	//

	class UX_EXPORT GLTextureBuffer : public GLTexture, protected GLBuffer
	{
	public:
		GLTextureBuffer ();
		
		// GLRenderTarget //
		virtual void Attach (GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel = 0, uint uLayer = 0);
		virtual bool Create (gl_rt_format::type eFormat, const uvec3 &vDim, uint8 uSamples = 0);

		bool Create (gl_tbo_iformat::type eIFormat);
		void Destroy ();

		bool AttachBuffer () const;
		bool AttachBuffer (GLBuffer *pBuffer) const;
		bool AttachBufferRange (GLBuffer *pBuffer, usize uOffset, usize uSize) const;
		
		void Bind () const					{ GLTexture::Bind(); }
		void Bind (uint8 uStage) const		{ GLTexture::Bind( uStage ); }
		void Unbind (uint8 uStage) const	{ GLTexture::Unbind( uStage ); }
		void Unbind () const				{ GLTexture::Unbind(); }

		GLBuffer *	Buffer ()				{ return (GLBuffer *)this; }
	};



	//
	// Texture Dynamic Buffer
	//

	class UX_EXPORT GLTextureDynBuffer : public GLTextureBuffer
	{
	protected:
		binary_array_t		_aBuffer;
		uint16				_uElemSize;

	private:
		bool Create (gl_tbo_iformat::type eIFormat) { return false; }

	public:
		GLTextureDynBuffer ();
		
		bool Create (gl_tbo_iformat::type eIFormat, uint16 uElemSize, usize uReserve = 0);
		void Destroy ();

		bool UpdateBuffer ();
		bool Resize (usize uElemCount);
		bool PushBackElem (const void *pData, usize uSize);
		bool SetElem (usize uNumb, const void *pData, usize uSize);

		binary_array_t const &	Data ()	const	{ return _aBuffer; }
	};




	//
	// Texture Buffer Format
	//

	struct GLTexFormatInfo::GLTextureBufferFormat
	{/*
#	define __DEF_FORMAT_N( _type, _size, _norm, _fmt ) \
		template <>	struct Format<_type,_norm,_size> { enum { value = gl_tbo_iformat::_fmt }; }

#	define __DEF_FORMAT( _type, _size, _fmt ) \
		__DEF_FORMAT_N( _type, _size, true, _fmt );		__DEF_FORMAT_N( _type, _size, false, _fmt )

		template <typename T, uint8 Size, bool bNorm>	struct Format { enum { value = gl_tbo_iformat::_UNKNOWN }; };

		__DEF_FORMAT( float, 1, R32F );
		__DEF_FORMAT( float, 2, RG32F );
		__DEF_FORMAT( float, 3, RGB32F );
		__DEF_FORMAT( float, 4, RGBA32F );

		__DEF_FORMAT_N( uint8, 1, true, R8 );*/
	};



//-------------------------- GLTexSwizzle -------------------------//

	inline bool GLTexSwizzle::operator == (const GLTexSwizzle &right) const
	{
		return	chR == right.chR and chG == right.chG and chB == right.chB and chA == right.chA;
	}

	inline bool GLTexSwizzle::operator != (const GLTexSwizzle &right) const
	{
		return not ( *this == right );
	}

	inline void GLTexSwizzle::ToArray(GLint aSwizzle[4]) const
	{
		static const GLint	s_aSwizzleParams[7] = { GL_ZERO, GL_ONE, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };

		aSwizzle[0] = s_aSwizzleParams[ chR ];
		aSwizzle[1] = s_aSwizzleParams[ chG ];
		aSwizzle[2] = s_aSwizzleParams[ chB ];
		aSwizzle[3] = s_aSwizzleParams[ chA ];
	}

	inline void GLTexSwizzle::FromArray(const GLint aSwizzle[4])
	{
		static const GLint	s_aSwizzleParams[] = { GL_ZERO, GL_ONE, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };

		for (usize i = 0; i < CountOf(s_aSwizzleParams); ++i)
		{
			if ( aSwizzle[0] == s_aSwizzleParams[i] )	chR = i;
			if ( aSwizzle[1] == s_aSwizzleParams[i] )	chG = i;
			if ( aSwizzle[2] == s_aSwizzleParams[i] )	chB = i;
			if ( aSwizzle[3] == s_aSwizzleParams[i] )	chA = i;
		}
	}
	


//--------------------------- GLTexture ---------------------------//
/*
=================================================
	устанавливает текстуру текущей
=================================================
*/
	inline void GLTexture::Bind() const
	{
		SMAN()->BindTexture( _eTarget, _uID );
	}

	inline void GLTexture::Bind(uint8 uStage) const
	{
		SMAN()->BindMultiTexture( uStage, _eTarget, _uID );
	}
	
/*
=================================================
	отключает текстуру
=================================================
*/
	inline void GLTexture::Unbind(uint8 uStage) const
	{
		SMAN()->BindMultiTexture( uStage, _eTarget, 0 );
	}

	inline void GLTexture::Unbind() const
	{
		SMAN()->BindTexture( _eTarget, 0 );
	}
	
/*
=================================================
	устанавливает текущим уровень текстуры
=================================================
*/
	inline void GLTexture::BindImage(uint8 uStage, gl_access::type eAccess, uint uLevel) const
	{
		ASSERT( IsImageSupported() and "image binding not supported for this format or with this version" );
		GL_CALL( glBindImageTexture( uStage, _uID, uLevel, GL_FALSE, 0, eAccess, _eIFormat ) );
	}

	inline void GLTexture::BindImage(uint8 uStage, uint uLayer, gl_access::type eAccess, uint uLevel) const
	{
		ASSERT( IsImageSupported() and "image binding not supported for this format or with this version" );
		GL_CALL( glBindImageTexture( uStage, _uID, uLevel, GL_TRUE, uLayer, eAccess, _eIFormat ) );
	}

	inline void GLTexture::UnbindImage(uint8 uStage) const
	{
		ASSERT( IsImageSupported() and "image binding not supported for this format or with this version" );
		GL_CALL( glBindImageTexture( uStage, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8 ) );
	}

/*
=================================================
	создает мип уровни для текстуры
=================================================
*/
	inline bool GLTexture::GenerateMipmaps() const
	{
		CHECK_ERR( C_GL_ARB_framebuffer_object );

		GL_CALL_R( glGenerateTextureMipmap( _uID, _eTarget ) );
		return true;
	}
	
/*
=================================================
	установить базовый уровень детализации текстуры
=================================================
*/
	inline void GLTexture::SetBaseLevel(int iLevel) const
	{
		GL_CALL( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_BASE_LEVEL, iLevel ) );
	}
	
/*
=================================================
	возвращает разрешение текстуры
	с заданным уроовнем детализации
=================================================
*/
	inline uvec3 const GLTexture::LevelDimension(uint i) const
	{
		switch ( _eTarget )
		{
			case gl_texture::TEXTURE_2D :
			case gl_texture::TEXTURE_3D :
			case gl_texture::TEXTURE_RECTANGLE :
			case gl_texture::TEXTURE_2D_MULTISAMPLE :
				return uvec3( Max( _vDimension.xy() >> i, uvec2(1) ), 0 );
				
			case gl_texture::TEXTURE_CUBE_MAP :
			case gl_texture::TEXTURE_2D_ARRAY :
			case gl_texture::TEXTURE_CUBE_MAP_ARRAY :
			case gl_texture::TEXTURE_2D_MULTISAMPLE_ARRAY :
				return uvec3( Max( _vDimension.xy() >> i, uvec2(1) ), _vDimension.z );

			case gl_texture::TEXTURE_1D :
			case gl_texture::TEXTURE_1D_ARRAY :
				return uvec3( Max( _vDimension.x >> i, 1u ), _vDimension.y, 0 );
		}

		WARNING( "Unsupported texture target!" );
		return uvec3(0);
	}



//------------------------ GLTextureBuffer ------------------------//
/*
=================================================
	присоединяет буфер к тукстуре
=================================================
*/
	inline bool GLTextureBuffer::AttachBuffer() const
	{
		GL_CALL_R( glTextureBuffer( GLTexture::_uID, GLTexture::Target(), _eIFormat, GLBuffer::_uID ) );
		return true;
	}

	inline bool GLTextureBuffer::AttachBuffer(GLBuffer *pBuffer) const
	{
		CHECK_ERR( pBuffer != null );
		GL_CALL_R( glTextureBuffer( GLTexture::_uID, GLTexture::Target(), _eIFormat, pBuffer->Id() ) );
		return true;
	}
	
	inline bool GLTextureBuffer::AttachBufferRange(GLBuffer *pBuffer, usize uOffset, usize uSize) const
	{
		CHECK_ERR( pBuffer != null );
		GL_CALL_R( glTextureBufferRange( GLTexture::_uID, GLTexture::Target(), _eIFormat, pBuffer->Id(), uOffset, uSize ) );
		return true;
	}
	


//----------------------- GLTextureDynBuffer ----------------------//
/*
=================================================
	записать элемент в буфер
=================================================
*/
	inline bool GLTextureDynBuffer::SetElem(usize uNumb, const void *pData, usize uSize)
	{
		ASSERT( uNumb*_uElemSize < _aBuffer.Size() and uSize == _uElemSize );

		_aBuffer.Replace( uni_array< const uint8 >::FromVoid( pData, _uElemSize ), uNumb * _uElemSize );
		return true;
	}
	
/*
=================================================
	записать элемент в буфер
=================================================
*/
	inline bool GLTextureDynBuffer::PushBackElem(const void *pData, usize uSize)
	{
		ASSERT( uSize == _uElemSize and "incorrect element data");
		
		_aBuffer.Append( uni_array< const uint8 >::FromVoid( pData, _uElemSize ) );
		return true;
	}
	
/*
=================================================
	изменить размер буфера
=================================================
*/
	inline bool GLTextureDynBuffer::Resize(usize uElemCount)
	{
		_aBuffer.Resize( uElemCount * _uElemSize, false );
		return true;
	}
	
/*
=================================================
	записать данные в текстурный буфер
=================================================
*/
	inline bool GLTextureDynBuffer::UpdateBuffer()
	{
		CHECK_ERR( !_aBuffer.Empty() );
		CHECK_ERR( SetData( _aBuffer.ptr(), _aBuffer.Size(), gl_usage::STREAM_DRAW ) );
		CHECK_ERR( AttachBuffer() );
		return true;
	}

//-------------------------------------------------------------------

}	// GLShell
}	// UX_STL

#endif	// _UXS_GL_TEXTURE_H